home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
AmigActive 22
/
AACD 22.iso
/
AACD
/
Resources
/
Sound
/
AHI
/
Developer
/
drivers
/
filesave
/
filesave.c
< prev
next >
Wrap
C/C++ Source or Header
|
1998-01-03
|
29KB
|
1,259 lines
#define NO_PROTOS
#define NO_SAS_PRAGMAS
#include <iffp/8svx.h>
#undef NO_PROTOS
#undef NO_SAS_PRAGMAS
#include <exec/exec.h>
#include <devices/ahi.h>
#include <dos/dos.h>
#include <dos/dostags.h>
#include <graphics/gfxbase.h>
#include <libraries/ahi_sub.h>
#include <libraries/asl.h>
#include <datatypes/datatypes.h>
#include <datatypes/soundclass.h>
#include <proto/asl.h>
#include <proto/exec.h>
#include <proto/dos.h>
#include <proto/intuition.h>
#include <proto/utility.h>
#include <proto/datatypes.h>
#include <proto/ahi_sub.h>
#include <stdlib.h>
#include "filesave.h"
#define dd ((struct filesave *) AudioCtrl->ahiac_DriverData)
#define SAVEBUFFERSIZE 100000 // in samples (min)
#define RECBUFFERSIZE 10000 // in samples
struct AIFCheader {
ULONG FORMid;
ULONG FORMsize;
ULONG AIFCid;
ULONG FVERid;
ULONG FVERsize;
FormatVersionHeader FVERchunk;
ULONG COMMid;
ULONG COMMsize;
ExtCommonChunk COMMchunk;
ULONG SSNDid;
ULONG SSNDsize;
SampledSoundHeader SSNDchunk;
};
struct AIFFheader {
ULONG FORMid;
ULONG FORMsize;
ULONG AIFFid;
ULONG COMMid;
ULONG COMMsize;
CommonChunk COMMchunk;
ULONG SSNDid;
ULONG SSNDsize;
SampledSoundHeader SSNDchunk;
};
struct EIGHTSVXheader {
ULONG FORMid;
ULONG FORMsize;
ULONG EIGHTSVXid;
ULONG VHDRid;
ULONG VHDRsize;
Voice8Header VHDRchunk;
ULONG BODYid;
ULONG BODYsize;
};
extern char __far _LibID[];
extern char __far _LibName[];
extern void KPrintF(char *fmt,...);
#define FREQUENCIES 23
const ULONG frequency[FREQUENCIES] =
{
5513,
6615,
8000, // µ- and A-Law
9600, // DAT/5
11025, // CD/4
12000, // DAT/4
14700, // CD/3
16000, // DAT/3
17640, // CD/2.5
18900,
19200, // DAT/2.5
22050, // CD/2
24000, // DAT/2
27429,
29400, // CD/1.5
32000, // DAT/1.5
33075,
37800,
44056, // Some kind of video rate
44100, // CD
48000, // DAT
88200, // CD*2
96000 // DAT*2
};
extern void SlaveEntry(void);
extern void RecSlaveEntry(void);
void ulong2extended (ULONG in, extended *ex);
struct DosLibrary *DOSBase = NULL;
struct Library *UtilityBase = NULL;
struct Library *AslBase = NULL;
struct IntuitionBase *IntuitionBase = NULL;
struct Library *AHIsubBase = NULL;
struct Library *DataTypesBase = NULL;
struct GfxBase *GfxBase = NULL;
int __saveds __asm __UserLibInit (register __a6 struct Library *libbase)
{
AHIsubBase = libbase;
if(!(DOSBase = (struct DosLibrary *) OpenLibrary("dos.library", 37)))
{
Alert(AN_Unknown|AG_OpenLib|AO_DOSLib);
return 1;
}
if(!(GfxBase = (struct GfxBase *) OpenLibrary("graphics.library", 37)))
{
Alert(AN_Unknown|AG_OpenLib|AO_GraphicsLib);
return 1;
}
if(!(IntuitionBase = (struct IntuitionBase *) OpenLibrary("intuition.library", 37)))
{
Alert(AN_Unknown|AG_OpenLib|AO_Intuition);
return 1;
}
if(!(UtilityBase = OpenLibrary("utility.library", 37)))
{
Alert(AN_Unknown|AG_OpenLib|AO_UtilityLib);
return 1;
}
// Don't fail if these ones don't open!
if(!(AslBase = OpenLibrary("asl.library", 37)))
{
struct EasyStruct req = {
sizeof (struct EasyStruct), 0, _LibName,
"Cannot open 'asl.library' v37", "OK"};
EasyRequest( NULL, &req, NULL, NULL );
}
DataTypesBase = OpenLibrary("datatypes.library",39);
return 0;
}
void __saveds __asm __UserLibCleanup (register __a6 struct Library *libbase)
{
if(AslBase) { CloseLibrary(AslBase); AslBase = NULL; }
if(DOSBase) { CloseLibrary((struct Library *)DOSBase); DOSBase = NULL; }
if(GfxBase) { CloseLibrary((struct Library *)GfxBase); GfxBase = NULL; }
if(IntuitionBase) { CloseLibrary((struct Library *)IntuitionBase); IntuitionBase = NULL; }
if(UtilityBase) { CloseLibrary(UtilityBase); UtilityBase = NULL; }
if(DataTypesBase) { CloseLibrary(DataTypesBase); DataTypesBase = NULL; }
}
ULONG __asm __saveds intAHIsub_AllocAudio(
register __a1 struct TagItem *tagList,
register __a2 struct AHIAudioCtrlDrv *AudioCtrl )
{
char *ext = "";
if(AslBase == NULL)
{
return AHISF_ERROR;
}
if(AudioCtrl->ahiac_DriverData = AllocVec(sizeof(struct filesave),MEMF_CLEAR))
{
dd->fs_AHIsubBase = AHIsubBase;
dd->fs_DisableSignal = -1;
dd->fs_EnableSignal = -1;
dd->fs_SlaveSignal = -1;
dd->fs_MasterSignal = AllocSignal(-1);
dd->fs_MasterTask = (struct Process *) FindTask(NULL);
dd->fs_RecSlaveSignal = -1;
dd->fs_RecMasterSignal = AllocSignal(-1);
}
else
{
return AHISF_ERROR;
}
if((dd->fs_MasterSignal == -1) || (dd->fs_RecMasterSignal == -1))
{
return AHISF_ERROR;
}
dd->fs_Format = GetTagData(AHIDB_FileSaveFormat, FORMAT_8SVX, tagList);
switch(dd->fs_Format)
{
case FORMAT_8SVX:
ext = ".8SVX";
break;
case FORMAT_AIFF:
ext = ".AIFF";
break;
case FORMAT_AIFC:
ext = ".AIFC";
break;
case FORMAT_S16:
break;
default:
break;
}
if(!(dd->fs_FileReq = AllocAslRequestTags(ASL_FileRequest,
ASLFR_InitialFile, ext,
ASLFR_DoSaveMode, TRUE,
ASLFR_RejectIcons, TRUE,
ASLFR_TitleText, _LibID,
TAG_DONE)))
{
return AHISF_ERROR;
}
if(!(dd->fs_RecFileReq = AllocAslRequestTags(ASL_FileRequest,
ASLFR_RejectIcons, TRUE,
ASLFR_TitleText, "Select a sound sample",
TAG_DONE)))
{
return AHISF_ERROR;
}
return AHISF_KNOWHIFI|AHISF_KNOWSTEREO|AHISF_CANRECORD|AHISF_MIXING|AHISF_TIMING;
}
void __asm __saveds intAHIsub_FreeAudio(
register __a2 struct AHIAudioCtrlDrv *AudioCtrl )
{
if(AudioCtrl->ahiac_DriverData)
{
FreeAslRequest(dd->fs_FileReq);
FreeAslRequest(dd->fs_RecFileReq);
FreeSignal(dd->fs_MasterSignal);
FreeSignal(dd->fs_RecMasterSignal);
FreeVec(AudioCtrl->ahiac_DriverData);
AudioCtrl->ahiac_DriverData = NULL;
}
}
ULONG __asm __saveds intAHIsub_Start(
register __d0 ULONG Flags,
register __a2 struct AHIAudioCtrlDrv *AudioCtrl )
{
AHIsub_Stop(Flags, AudioCtrl);
if(Flags & AHISF_PLAY)
{
ULONG savebufferlength;
if(!(dd->fs_MixBuffer = AllocVec(AudioCtrl->ahiac_BuffSize, MEMF_ANY)))
return AHIE_NOMEM;
dd->fs_SaveBufferSize = AudioCtrl->ahiac_MaxBuffSamples;
// S16 has two buffers (L/R) instead
if((AudioCtrl->ahiac_Flags & AHIACF_STEREO) && dd->fs_Format != FORMAT_S16)
{
dd->fs_SaveBufferSize <<=1;
}
if(dd->fs_SaveBufferSize < SAVEBUFFERSIZE)
{
dd->fs_SaveBufferSize = SAVEBUFFERSIZE;
}
savebufferlength = dd->fs_SaveBufferSize;
switch(dd->fs_Format)
{
case FORMAT_8SVX:
break;
case FORMAT_AIFF:
savebufferlength <<= 1;
break;
case FORMAT_AIFC:
savebufferlength <<= 1;
break;
case FORMAT_S16:
savebufferlength <<= 1;
break;
default:
break;
}
if(!(dd->fs_SaveBuffer = AllocVec(savebufferlength, MEMF_ANY)))
{
return AHIE_NOMEM;
}
if ((AudioCtrl->ahiac_Flags & AHIACF_STEREO) && dd->fs_Format == FORMAT_S16)
{
if(!(dd->fs_SaveBuffer2 = AllocVec(savebufferlength, MEMF_ANY)))
{
return AHIE_NOMEM;
}
}
if(AslRequestTags(dd->fs_FileReq,TAG_DONE))
{
Forbid();
if(dd->fs_SlaveTask = CreateNewProcTags(
NP_Entry, SlaveEntry,
NP_Name, _LibName,
NP_Priority, -1, // It's a number cruncher...
NP_StackSize, 10000,
TAG_DONE))
{
dd->fs_SlaveTask->pr_Task.tc_UserData = AudioCtrl;
}
Permit();
if(dd->fs_SlaveTask)
{
Wait(1L<<dd->fs_MasterSignal); // Wait for slave to come alive
if(dd->fs_SlaveTask == NULL) // Is slave alive or dead?
{
return AHIE_UNKNOWN;
}
}
else
{
return AHIE_NOMEM;
}
}
else
{
if(IoErr())
{
return AHIE_NOMEM; //error occured
}
else
{
return AHIE_ABORTED; //requester cancelled
}
}
}
if(Flags & AHISF_RECORD)
{
if(!(dd->fs_RecBuffer = AllocVec(RECBUFFERSIZE*4,MEMF_ANY)))
{
return AHIE_NOMEM;
}
if(AslRequestTags(dd->fs_RecFileReq,TAG_DONE))
{
Delay(TICKS_PER_SECOND); // Wait for window to close etc...
Forbid();
if(dd->fs_RecSlaveTask = CreateNewProcTags(
NP_Entry, RecSlaveEntry,
NP_Name, _LibName,
NP_Priority, 1, // Make it steady...
TAG_DONE))
{
dd->fs_RecSlaveTask->pr_Task.tc_UserData = AudioCtrl;
}
Permit();
if(dd->fs_RecSlaveTask)
{
Wait(1L<<dd->fs_RecMasterSignal); // Wait for slave to come alive
if(dd->fs_RecSlaveTask == NULL) // Is slave alive or dead?
{
return AHIE_UNKNOWN;
}
}
else
{
return AHIE_NOMEM;
}
}
else
{
if(IoErr())
{
return AHIE_NOMEM; //error occured
}
else
{
return AHIE_ABORTED; //requester cancelled
}
}
}
return AHIE_OK;
}
void __asm __saveds intAHIsub_Update(
register __d0 ULONG Flags,
register __a2 struct AHIAudioCtrlDrv *AudioCtrl )
{
}
void __asm __saveds intAHIsub_Stop(
register __d0 ULONG Flags,
register __a2 struct AHIAudioCtrlDrv *AudioCtrl )
{
if(Flags & AHISF_PLAY)
{
if(dd->fs_SlaveTask)
{
if(dd->fs_SlaveSignal != -1)
{
Signal((struct Task *)dd->fs_SlaveTask,1L<<dd->fs_SlaveSignal); // Kill him!
}
Wait(1L<<dd->fs_MasterSignal); // Wait for slave to die
}
FreeVec(dd->fs_MixBuffer);
dd->fs_MixBuffer = NULL;
FreeVec(dd->fs_SaveBuffer);
FreeVec(dd->fs_SaveBuffer2);
dd->fs_SaveBuffer = NULL;
dd->fs_SaveBuffer2 = NULL;
}
if(Flags & AHISF_RECORD)
{
if(dd->fs_RecSlaveTask)
{
if(dd->fs_RecSlaveSignal != -1)
{
Signal((struct Task *)dd->fs_RecSlaveTask,1L<<dd->fs_RecSlaveSignal); // Kill him!
}
Wait(1L<<dd->fs_RecMasterSignal); // Wait for slave to die
}
FreeVec(dd->fs_RecBuffer);
dd->fs_RecBuffer = NULL;
}
}
LONG __asm __saveds intAHIsub_GetAttr(
register __d0 ULONG Attribute,
register __d1 LONG Argument,
register __d2 LONG Default,
register __a1 struct TagItem *tagList,
register __a2 struct AHIAudioCtrlDrv *AudioCtrl)
{
int i;
switch(Attribute)
{
case AHIDB_Bits:
switch (GetTagData(AHIDB_FileSaveFormat,FORMAT_8SVX,tagList))
{
case FORMAT_8SVX:
return 8;
case FORMAT_AIFF:
return 16;
case FORMAT_AIFC:
return 16;
case FORMAT_S16:
return 16;
default:
return Default;
}
case AHIDB_Frequencies:
return FREQUENCIES;
case AHIDB_Frequency: // Index->Frequency
return (LONG) frequency[Argument];
case AHIDB_Index: // Frequency->Index
if(Argument <= frequency[0])
{
return 0;
}
if(Argument >= frequency[FREQUENCIES-1])
{
return FREQUENCIES-1;
}
for(i = 1;i<FREQUENCIES;i++)
{
if(frequency[i]>Argument)
{
if( (Argument-frequency[i-1]) < (frequency[i]-Argument) )
{
return i-1;
}
else
{
return i;
}
}
}
return 0; // Will not happen
case AHIDB_Author:
return (LONG) "Martin 'Leviticus' Blom";
case AHIDB_Copyright:
return (LONG) "Public Domain";
case AHIDB_Version:
return (LONG) _LibID;
case AHIDB_Record:
return TRUE;
case AHIDB_FullDuplex:
return TRUE;
case AHIDB_MaxRecordSamples:
return RECBUFFERSIZE;
case AHIDB_Realtime:
return FALSE;
case AHIDB_Inputs:
return 1;
case AHIDB_Input:
return (LONG) "File"; // We have only one input!
case AHIDB_Outputs:
return 1;
case AHIDB_Output:
return (LONG) "File"; // We have only one output!
default:
return Default;
}
}
ULONG __asm __saveds intAHIsub_HardwareControl(
register __d0 ULONG attribute,
register __d1 LONG argument,
register __a2 struct AHIAudioCtrlDrv *AudioCtrl )
{
return NULL;
}
/*
** Unused LVOs follows...
*/
ULONG __asm __saveds intAHIsub_SetVol(
register __d0 UWORD channel,
register __d1 Fixed volume,
register __d2 sposition pan,
register __a2 struct AHIAudioCtrlDrv *AudioCtrl,
register __d3 ULONG Flags)
{
return AHIS_UNKNOWN;
}
ULONG __asm __saveds intAHIsub_SetFreq(
register __d0 UWORD channel,
register __d1 ULONG freq,
register __a2 struct AHIAudioCtrlDrv *AudioCtrl,
register __d2 ULONG flags )
{
return AHIS_UNKNOWN;
}
ULONG __asm __saveds intAHIsub_SetSound(
register __d0 UWORD channel,
register __d1 UWORD sound,
register __d2 ULONG offset,
register __d3 LONG length,
register __a2 struct AHIAudioCtrlDrv *AudioCtrl,
register __d4 ULONG flags )
{
return AHIS_UNKNOWN;
}
ULONG __asm __saveds intAHIsub_SetEffect (
register __a0 APTR effect,
register __a2 struct AHIAudioCtrlDrv *AudioCtrl )
{
return AHIS_UNKNOWN;
}
ULONG __asm __saveds intAHIsub_LoadSound(
register __d0 UWORD sound,
register __d1 ULONG type,
register __a0 APTR info,
register __a2 struct AHIAudioCtrlDrv *AudioCtrl )
{
return AHIS_UNKNOWN;
}
ULONG __asm __saveds intAHIsub_UnloadSound(
register __d0 UWORD sound,
register __a2 struct AHIAudioCtrlDrv *AudioCtrl )
{
return AHIS_UNKNOWN;
}
/*
** The slave process
*/
void __asm __saveds SlaveTask(register __a2 struct AHIAudioCtrlDrv *AudioCtrl)
// SlaveEntry() will set up register a2 and a6 for us.
{
struct EIGHTSVXheader EIGHTSVXheader = // All NULLs will be filled later.
{
ID_FORM, NULL, ID_8SVX,
ID_VHDR, sizeof(Voice8Header),
{
NULL,
0,
0,
NULL,
1,
sCmpNone,
0x10000
},
ID_BODY, NULL
};
struct AIFFheader AIFFheader = // All NULLs will be filled later.
{
ID_FORM, NULL, ID_AIFF,
ID_COMM, sizeof(CommonChunk),
{
NULL,
NULL,
16,
{
NULL
}
},
ID_SSND, NULL,
{
0,
0
}
};
struct AIFCheader AIFCheader = // All NULLs will be filled later.
{
ID_FORM, NULL, ID_AIFC,
ID_FVER, sizeof(FormatVersionHeader),
{
AIFCVersion1
},
ID_COMM, sizeof(ExtCommonChunk),
{
NULL,
NULL,
16,
{
NULL
},
NO_COMPRESSION,
sizeof("not compressed") - 1,
'n','o','t',' ','c','o','m','p','r','e','s','s','e','d'
},
ID_SSND, NULL,
{
0,
0
}
};
struct STUDIO16FILE S16header = // All NULLs will be filled later.
{
S16FID,
NULL,
S16FINIT,
S16_VOL_0,
0,
0,
NULL,
0,
0,
NULL,
NULL,
0,
NULL,
0,
{
0
}
};
struct EasyStruct req =
{
sizeof (struct EasyStruct),
0,
_LibID,
"Rendering finished.\nTo futher improve the quality of the sample,\n"
"you can raise the volume to %ld%%%sand render again.",
"OK",
};
BPTR lock = NULL,cd = NULL,file = NULL, file2 = NULL;
ULONG signals, i, maxVolume = 0, samples, length;
ULONG offset = 0, bytesInBuffer = 0, samplesWritten = 0, bytesWritten = 0;
// We cannot handle stereo 8SVXs!
if( (dd->fs_Format == FORMAT_8SVX) &&
(AudioCtrl->ahiac_Flags & AHIACF_STEREO) )
{
goto quit;
}
if((dd->fs_DisableSignal = AllocSignal(-1)) == -1)
{
goto quit;
}
if((dd->fs_EnableSignal = AllocSignal(-1)) == -1)
{
goto quit;
}
if((dd->fs_SlaveSignal = AllocSignal(-1)) == -1)
{
goto quit;
}
if(!(lock = Lock(dd->fs_FileReq->fr_Drawer, ACCESS_READ)))
{
goto quit;
}
cd = CurrentDir(lock);
switch(dd->fs_Format)
{
case FORMAT_8SVX:
if(!(file = Open(dd->fs_FileReq->fr_File, MODE_NEWFILE))) goto quit;
Write(file, &EIGHTSVXheader, sizeof EIGHTSVXheader);
break;
case FORMAT_AIFF:
if(!(file = Open(dd->fs_FileReq->fr_File, MODE_NEWFILE))) goto quit;
Write(file, &AIFFheader, sizeof AIFFheader);
break;
case FORMAT_AIFC:
if(!(file = Open(dd->fs_FileReq->fr_File, MODE_NEWFILE))) goto quit;
Write(file, &AIFCheader, sizeof AIFCheader);
break;
case FORMAT_S16:
if (AudioCtrl->ahiac_Flags & AHIACF_STEREO)
{
char filename[256];
int len;
strncpy (filename, dd->fs_FileReq->fr_File, sizeof(filename) - 3);
len = strlen(filename);
if(len >= 2 && filename[len - 2] == '_'
&& (filename[len - 1] == 'L' || filename[len - 1] == 'R'))
{
filename[len - 1] = 'L';
}
else
{
strcat (filename, "_L");
}
if(!(file = Open(filename, MODE_NEWFILE))) goto quit;
filename[strlen(filename) - 1] = 'R';
if(!(file2 = Open(filename, MODE_NEWFILE))) goto quit;
Write(file, &S16header, sizeof S16header);
Write(file2, &S16header, sizeof S16header);
}
else
{
if(!(file = Open(dd->fs_FileReq->fr_File, MODE_NEWFILE))) goto quit;
Write(file, &S16header, sizeof S16header);
}
break;
}
// Everything set up. Tell Master we're alive and healthy.
Signal((struct Task *)dd->fs_MasterTask,1L<<dd->fs_MasterSignal);
for(;;)
{
signals = SetSignal(0L,0L);
if(signals & (SIGBREAKF_CTRL_C | 1L<<dd->fs_SlaveSignal))
{
break;
}
if(signals & (1L<<dd->fs_EnableSignal | 1L<<dd->fs_DisableSignal) == 1L<<dd->fs_DisableSignal)
{
Wait(1L<<dd->fs_EnableSignal);
}
CallHookPkt(AudioCtrl->ahiac_PlayerFunc, AudioCtrl, NULL);
CallHookPkt(AudioCtrl->ahiac_MixerFunc, AudioCtrl, dd->fs_MixBuffer);
samples = AudioCtrl->ahiac_BuffSamples;
if(AudioCtrl->ahiac_Flags & AHIACF_STEREO)
{
samples <<= 1;
}
// Search for loudest part in sample
if(AudioCtrl->ahiac_Flags & AHIACF_HIFI)
{
for(i = 0; i < samples; i++)
if(abs(((LONG *)dd->fs_MixBuffer)[i]) > maxVolume)
maxVolume = abs(((LONG *)dd->fs_MixBuffer)[i]);
}
else
{
for(i = 0; i< samples; i++)
if(abs(((WORD *)dd->fs_MixBuffer)[i]) > maxVolume)
maxVolume = abs(((WORD *)dd->fs_MixBuffer)[i]);
}
if((AudioCtrl->ahiac_Flags & AHIACF_STEREO) && dd->fs_Format == FORMAT_S16)
{
samples >>= 1; // Two buffers instead
}
if(offset+samples >= dd->fs_SaveBufferSize)
{
if(Write(file, dd->fs_SaveBuffer, bytesInBuffer) != bytesInBuffer)
{
break;
}
if(file2 != NULL) {
if(Write(file2, dd->fs_SaveBuffer2, bytesInBuffer) != bytesInBuffer)
{
break;
}
}
offset = 0;
bytesInBuffer = 0;
}
switch(dd->fs_Format)
{
case FORMAT_8SVX:
if(AudioCtrl->ahiac_Flags & AHIACF_HIFI)
{
BYTE *dest = &((BYTE *) dd->fs_SaveBuffer)[offset];
LONG *source = dd->fs_MixBuffer;
for(i = 0; i < samples; i++)
*dest++ = *source++ >> 24;
}
else
{
BYTE *dest = &((BYTE *) dd->fs_SaveBuffer)[offset];
WORD *source = dd->fs_MixBuffer;
for(i = 0; i < samples; i++)
*dest++ = *source++ >> 8;
}
length = samples;
break;
case FORMAT_AIFF:
case FORMAT_AIFC:
if(AudioCtrl->ahiac_Flags & AHIACF_HIFI)
{
WORD *dest = &((WORD *) dd->fs_SaveBuffer)[offset];
LONG *source = dd->fs_MixBuffer;
for(i = 0; i < samples; i++)
{
*dest++ = *source++ >> 16;
}
}
else
{
WORD *dest = &((WORD *) dd->fs_SaveBuffer)[offset];
WORD *source = dd->fs_MixBuffer;
for(i = 0; i < samples; i++)
{
*dest++ = *source++;
}
}
length = samples*2;
break;
case FORMAT_S16:
switch(AudioCtrl->ahiac_Flags & (AHIACF_HIFI | AHIACF_STEREO))
{
case 0:
{
WORD *dest = &((WORD *) dd->fs_SaveBuffer)[offset];
WORD *source = dd->fs_MixBuffer;
for(i = 0; i < samples; i++)
{
*dest++ = *source++;
}
length = i*2;
break;
}
case AHIACF_STEREO:
{
WORD *dest1 = &((WORD *) dd->fs_SaveBuffer)[offset];
WORD *dest2 = &((WORD *) dd->fs_SaveBuffer2)[offset];
WORD *source = dd->fs_MixBuffer;
for(i = 0; i < samples; i++)
{
*dest1++ = *source++;
*dest2++ = *source++;
}
length = i*2;
break;
}
case AHIACF_HIFI:
{
WORD *dest = &((WORD *) dd->fs_SaveBuffer)[offset];
LONG *source = dd->fs_MixBuffer;
for(i = 0; i < samples; i++)
{
*dest++ = *source++ >> 16;
}
length = i*2;
break;
}
case (AHIACF_HIFI | AHIACF_STEREO):
{
WORD *dest1 = &((WORD *) dd->fs_SaveBuffer)[offset];
WORD *dest2 = &((WORD *) dd->fs_SaveBuffer2)[offset];
LONG *source = dd->fs_MixBuffer;
for(i = 0; i < samples; i++)
{
*dest1++ = *source++ >> 16;
*dest2++ = *source++ >> 16;
}
break;
}
}
length = samples*2;
break;
}
offset += samples;
samplesWritten += AudioCtrl->ahiac_BuffSamples;
bytesWritten += length;
bytesInBuffer += length;
}
Write(file, dd->fs_SaveBuffer, bytesInBuffer);
if(file2 != NULL)
{
Write(file2, dd->fs_SaveBuffer2, bytesInBuffer);
}
switch(dd->fs_Format)
{
case FORMAT_8SVX:
EIGHTSVXheader.FORMsize = sizeof(EIGHTSVXheader)-8+bytesWritten;
EIGHTSVXheader.VHDRchunk.oneShotHiSamples = samplesWritten;
EIGHTSVXheader.VHDRchunk.samplesPerSec = AudioCtrl->ahiac_MixFreq;
EIGHTSVXheader.BODYsize = bytesWritten;
if(bytesWritten & 1)
FPutC(file,'\0'); // Pad to even
Seek(file,0,OFFSET_BEGINNING);
Write(file,&EIGHTSVXheader,sizeof EIGHTSVXheader);
break;
case FORMAT_AIFF:
AIFFheader.FORMsize = sizeof(AIFFheader)-8+bytesWritten;
AIFFheader.COMMchunk.numChannels = (AudioCtrl->ahiac_Flags & AHIACF_STEREO ? 2 : 1);
AIFFheader.COMMchunk.numSampleFrames = samplesWritten;
ulong2extended(AudioCtrl->ahiac_MixFreq,&AIFFheader.COMMchunk.sampleRate);
AIFFheader.SSNDsize = sizeof(SampledSoundHeader)+bytesWritten;
Seek(file,0,OFFSET_BEGINNING);
Write(file,&AIFFheader,sizeof AIFFheader);
break;
case FORMAT_AIFC:
AIFCheader.FORMsize = sizeof(AIFCheader)-8+bytesWritten;
AIFCheader.COMMchunk.numChannels = (AudioCtrl->ahiac_Flags & AHIACF_STEREO ? 2 : 1);
AIFCheader.COMMchunk.numSampleFrames = samplesWritten;
ulong2extended(AudioCtrl->ahiac_MixFreq,&AIFCheader.COMMchunk.sampleRate);
AIFCheader.SSNDsize = sizeof(SampledSoundHeader)+bytesWritten;
Seek(file,0,OFFSET_BEGINNING);
Write(file,&AIFCheader,sizeof AIFCheader);
break;
case FORMAT_S16:
S16header.S16F_RATE = AudioCtrl->ahiac_MixFreq;
S16header.S16F_SAMPLES0 =
S16header.S16F_SAMPLES1 = samplesWritten;
S16header.S16F_SAMPLES2 = samplesWritten - 1;
if (file2 == NULL)
{
S16header.S16F_PAN = S16_PAN_MID;
}
else
{
S16header.S16F_PAN = S16_PAN_LEFT;
}
Seek(file, 0, OFFSET_BEGINNING);
Write(file, &S16header, sizeof S16header);
if(file2 != NULL)
{
S16header.S16F_PAN = S16_PAN_RIGHT;
Seek(file2,0,OFFSET_BEGINNING);
Write(file2, &S16header, sizeof S16header);
}
break;
}
if(AudioCtrl->ahiac_Flags & AHIACF_HIFI)
maxVolume >>=16;
if(maxVolume != 0)
{
EasyRequest(NULL, &req, NULL, 3276800/maxVolume,
AudioCtrl->ahiac_MixFreq<frequency[FREQUENCIES-1] ? ",\nincrease the mixing frequency " : "\n");
}
quit:
if(file)
{
Close(file);
}
if(file2)
{
Close(file2);
}
if(lock)
{
CurrentDir(cd);
UnLock(lock);
}
Forbid();
dd->fs_SlaveTask = NULL;
FreeSignal(dd->fs_DisableSignal);
FreeSignal(dd->fs_EnableSignal);
FreeSignal(dd->fs_SlaveSignal);
dd->fs_DisableSignal = -1;
dd->fs_EnableSignal = -1;
dd->fs_SlaveSignal = -1;
// Tell the Master we're dying
Signal((struct Task *)dd->fs_MasterTask,1L<<dd->fs_MasterSignal);
// Multitaking will resume when we are dead.
}
/*
** Apple's 80-bit SANE extended has the following format:
1 15 1 63
+-+-------------+-+-----------------------------+
|s| e |i| f |
+-+-------------+-+-----------------------------+
msb lsb msb lsb
The value v of the number is determined by these fields as follows:
If 0 <= e < 32767, then v = (-1)^s * 2^(e-16383) * (i.f).
If e == 32767 and f == 0, then v = (-1)^s * (infinity), regardless of i.
If e == 32767 and f != 0, then v is a NaN, regardless of i.
*/
void ulong2extended (ULONG in, extended *ex)
{
ex->exponent = 31+16383;
ex->mantissa[1] = 0;
while(!(in & 0x80000000))
{
ex->exponent--;
in <<= 1;
}
ex->mantissa[0] = in;
}
/*
** The record slave process
*/
void __asm __saveds RecSlaveTask(register __a2 struct AHIAudioCtrlDrv *AudioCtrl)
// RecSlaveEntry() will set up register a2 and a6 for us.
{
ULONG signals;
BPTR lock = NULL,cd,file = NULL;
Object *o = NULL;
BYTE *samples = NULL;
ULONG length = NULL;
ULONG count = 0,offs = 0,i;
struct AHIRecordMessage RecordMessage =
{
AHIST_S16S,
NULL,
RECBUFFERSIZE
};
RecordMessage.ahirm_Buffer = dd->fs_RecBuffer;
if(!(lock = Lock(dd->fs_RecFileReq->fr_Drawer,ACCESS_READ)))
goto quit;
cd = CurrentDir(lock);
if(DataTypesBase)
{
if (!(o = NewDTObject (dd->fs_RecFileReq->fr_File,
DTA_GroupID,GID_SOUND,
TAG_DONE)))
goto quit;
GetDTAttrs(o,
SDTA_Sample,&samples,
SDTA_SampleLength,&length,
TAG_DONE);
}
else // datatypes.library not open. Open the selected file as raw 8 bit signed instead.
{
if(!(file = Open(dd->fs_RecFileReq->fr_File,MODE_OLDFILE)))
goto quit;
Seek(file,0,OFFSET_END);
length = Seek(file,0,OFFSET_BEGINNING);
if(!(samples = AllocVec(length,MEMF_ANY)))
goto quit;
if(length != Read(file,samples,length))
goto quit;
}
if(!samples || !length )
goto quit;
if((dd->fs_RecSlaveSignal = AllocSignal(-1)) == -1)
goto quit;
// Everything set up. Tell Master we're alive and healthy.
Signal((struct Task *)dd->fs_MasterTask,1L<<dd->fs_RecMasterSignal);
for(;;)
{
signals = SetSignal(0L,0L);
if(signals & (SIGBREAKF_CTRL_C | 1L<<dd->fs_RecSlaveSignal))
break;
for(;;)
{
if(count+RECBUFFERSIZE-offs < length)
{
// End of sample will not be reached; just fill to the end of dd->fs_RecBuffer.
for(i = RECBUFFERSIZE-offs;i>0;i--)
{
dd->fs_RecBuffer[(offs)<<1] =
dd->fs_RecBuffer[((offs++)<<1)+1] =
samples[count++]<<8;
}
offs = 0;
break;
}
else
{
// End of sample will be reached. Fill part of buffer, and iterate (== don't break).
for(i = length-count;i>0;i--)
{
dd->fs_RecBuffer[(offs)<<1] =
dd->fs_RecBuffer[((offs++)<<1)+1] =
samples[count++]<<8;
}
count = 0;
}
}
CallHookPkt(AudioCtrl->ahiac_SamplerFunc,AudioCtrl,&RecordMessage);
Delay(50*RECBUFFERSIZE/AudioCtrl->ahiac_MixFreq);
}
quit:
// Get rid of object
if(DataTypesBase)
{
if(o)
DisposeDTObject (o);
}
else // datatypes.library not open.
{
if(samples)
FreeVec(samples);
if(file)
Close(file);
}
CurrentDir(cd);
if(lock)
UnLock(lock);
Forbid();
dd->fs_RecSlaveTask = NULL;
FreeSignal(dd->fs_RecSlaveSignal);
dd->fs_RecSlaveSignal = -1;
// Tell the Master we're dying
Signal((struct Task *)dd->fs_MasterTask,1L<<dd->fs_RecMasterSignal);
// Multitaking will resume when we are dead.
}